package com.foreveross.crawl.adapter.sub.impl20140402.v3;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.htmlcleaner.HtmlCleaner;
import org.htmlcleaner.TagNode;

import com.foreveross.crawl.adapter.AbstractAdapter;
import com.foreveross.crawl.adapter.CrawlAdapterFactory;
import com.foreveross.crawl.adapter.PlaneInfoEntityBuilder;
import com.foreveross.crawl.common.util.RegHtmlUtil;
import com.foreveross.crawl.common.util.StringUtils;
import com.foreveross.crawl.domain.airfreight.AbstractPlaneInfoEntity;
import com.foreveross.crawl.domain.airfreight.CabinEntity;
import com.foreveross.crawl.domain.airfreight.StopOverEntity;
import com.foreveross.crawl.domain.airfreight.TransitEntity;
import com.foreveross.crawl.domain.airfreight.single.SinglePlaneInfoEntity;
import com.foreveross.crawl.exception.FlightInfoNotFoundException;
import com.foreveross.taskservice.common.bean.TaskModel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;

/**
 * --> visit /search.aspx to prepare asp's viewstate.
 * ------> post /search.aspx.
 * ---------> extract flightKeys.
 * --------------> using flightKeys to fetch flt info.
 *
 * @author siuming
 */
public class AirAsiaAdapter extends AbstractAdapter {

    private static final String EMPTY_FLT_INFO = "";
    private static final String ECONOMIC_CABIN_NAME = "经济舱";
    private static final String FREQ_CABIN_NAME = "常旅客";
    private static final String BUSINESS_CABIN_NAME = "商务舱";

    private static final Map<String, String> CARRIER_MAPPINGS = new HashMap<String, String>() {
        {
            put("AK", "亚航");
            put("FD", "泰国亚航");
            put("FZ", "印尼亚航");
            put("D7", "亚航X");
            put("PQ", "菲律宾亚航");
            put("Z2", "AirAsia Zest");
            put("XJ", "Thai AirAsia X");
        }
    };

    private static final Map<String, String> CARRIER_FULLNAME_MAPPINGS = new HashMap<String, String>() {
        {
            put("AK", "亚州航空公司");
            put("FD", "泰国亚州航空公司");
            put("FZ", "印尼亚州航空公司");
            put("D7", "亚洲航空x有限公司");
            put("PQ", "菲律宾亚州航空公司");
            put("Z2", "亚航飞龙航空");
            put("XJ", "泰国亚洲航空X有限公司");
        }
    };

    /**
     * @param taskQueue
     */
    public AirAsiaAdapter(TaskModel taskQueue) {
        super(taskQueue);
    }

    @Override
    public String getUrl() throws Exception {
        return null;
    }

    /**
     * bad method name!
     *
     * @param fetchObject
     * @return
     * @throws Exception
     */
    @Override
    public List<Object> paraseToVo(Object fetchObject) throws Exception {
        switch (getRouteType()) {
            case DOMESTIC_ONEWAYTRIP:
            case INTERNATIONAL_ONEWAY:
                return parseOneway(fetchObject);
            default:
                return parseRoundway(fetchObject);
        }
    }

    @SuppressWarnings("unchecked")
	private List<Object> parseOneway(Object fetchObject) throws Exception {
        List<AirAsiaFltInfos> fltInfoses = (List<AirAsiaFltInfos>) fetchObject;
//        if (fltInfoses.isEmpty()) {
//        	throw new FlightInfoNotFoundException("没有符合搜索条件的航班");
//        }

        return (List<Object>)transformAsSinglePlaneInfos(fltInfoses.get(0));
    }

    private Object transformAsSinglePlaneInfos(AirAsiaFltInfos airAsiaFltInfos) throws Exception {
        HtmlCleaner cleaner = new HtmlCleaner();

        List<AbstractPlaneInfoEntity> results = Lists.newArrayList();
        for (String fltInfo : airAsiaFltInfos.economicFltInfos) {
            TagNode root = cleaner.clean(fltInfo);
            SinglePlaneInfoEntity planeInfo = transformSinglePlaneInfo(root, ECONOMIC_CABIN_NAME);
            if (null == planeInfo) {
                continue;
            }
            results.add(planeInfo);
        }

        for (String fltInfo : airAsiaFltInfos.freqFltInfos) {
            TagNode root = cleaner.clean(fltInfo);
            SinglePlaneInfoEntity planeInfo = transformSinglePlaneInfo(root, FREQ_CABIN_NAME);
            if (null == planeInfo) {
                continue;
            }
            results.add(planeInfo);
        }

        for (String fltInfo : airAsiaFltInfos.businessFltInfos) {
            TagNode root = cleaner.clean(fltInfo);
            SinglePlaneInfoEntity planeInfo = transformSinglePlaneInfo(root, BUSINESS_CABIN_NAME);
            if (null == planeInfo) {
                continue;
            }
            results.add(planeInfo);
        }
        PlaneInfoEntityBuilder.buildLimitPrice(results);
        return results;
    }

    private SinglePlaneInfoEntity transformSinglePlaneInfo(TagNode root, String cabinName) throws Exception {

        Object[] results = root.evaluateXPath("//div[@id='journey-section']/div[@class='flightDisplay_1'][1]");
        if (results.length == 0) {
            return null;
        }

        // may more than 2 fltsegs.
        int segs = 0;
        int airports = 0;

        ArrayList<TransitEntity> transits = Lists.newArrayList();
        for (; ; ) {
            Object[] fltnos = ((TagNode) results[0]).evaluateXPath(String.format("div[@class='row1'][%s]/span[1]/text()", ++segs));
            Object[] fltairports = ((TagNode) results[0]).evaluateXPath(String.format("div[@class='row2 mtop-row'][%s]/div/text()", ++airports));
            Object[] flttimes = ((TagNode) results[0]).evaluateXPath(String.format("div[@class='row1'][%s]/span/text()", ++segs));

            String fltno = fltnos[0].toString().replaceAll("\\s+", "");
            // if not santisfied ,it may end of the fltsegs ,break it and try to parse taxes and prices.
            if (fltnos.length!=1 || !fltno.matches("[\\w]{5,6}")) {
                break;
            }

            if (fltairports.length != 3) {
                break;
            }

            if (flttimes.length != 2) {
                break;
            }

            String carrier = fltno.substring(0, 2);
            TransitEntity transit = PlaneInfoEntityBuilder.buildTransitEntity(
                    fltno, "",
                    carrier, CARRIER_MAPPINGS.get(carrier), CARRIER_FULLNAME_MAPPINGS.get(carrier),
                    fltairports[0].toString(), "",
                    fltairports[2].toString(), "",
                    "",
                    TransitEntity.class
            );

            String starttime = StringUtils.trim(StringUtils.substringBefore(flttimes[0].toString(), ","));
            String endtime = StringUtils.trim(StringUtils.substringBefore(flttimes[1].toString(), ","));
            transit.setStartTime(CrawlAdapterFactory.getFlightTime(taskQueue.getFlightDate(), starttime));
            transit.setEndTime(CrawlAdapterFactory.getFlightTime(taskQueue.getFlightDate(), endtime));
            transits.add(transit);
        }

        if (transits.isEmpty()) {
            return null;
        }

        SimpleDateFormat HHmm = new SimpleDateFormat("HH:mm", Locale.ENGLISH);
        SinglePlaneInfoEntity planeInfo = PlaneInfoEntityBuilder.buildPlaneInfo(
                taskQueue, "AK", "亚航", "亚洲航空",
                HHmm.format(transits.get(0).getStartTime()), HHmm.format(transits.get(transits.size() - 1).getEndTime()),
                transits.get(0).getFlightNo(), "", null, "", "", SinglePlaneInfoEntity.class);

        try {
			Object[] flttaxes = ((TagNode) results[0]).evaluateXPath(String
					.format("div[@class='row1'][%s]/span[1]/text()", segs - 1));
			Object[] totalprices = ((TagNode) results[0]).evaluateXPath(String
					.format("div[@class='row1'][%s]/span[1]/text()", segs));
			String taxes = flttaxes[0].toString().replaceAll(",", "")
					.replaceAll("([0-9.]+)\\s+[\\w]+", "$1");
			String totalprice = totalprices[0].toString().replaceAll(",", "")
					.replaceAll("([0-9.]+)\\s+[\\w]+", "$1");
			String price = new BigDecimal(totalprice)
					.subtract(new BigDecimal(taxes))
					.setScale(2, BigDecimal.ROUND_HALF_UP).toString();
			CabinEntity cabin = PlaneInfoEntityBuilder.buildCabinInfo("", "",
					cabinName,taxes, price, totalprice, "", "", CabinEntity.class);
			if(transits.size()>1){ //如果只有一个中转（为航班）时不保存。
				PlaneInfoEntityBuilder.setTransits(planeInfo, transits);
			}
			PlaneInfoEntityBuilder.setCabin(planeInfo, ImmutableSet.of(cabin));
			// TODO
			// 0840  在  吉隆坡(KUL) 转机  在  KUL 0840
			Set<StopOverEntity> stopOverEntities = Sets.newHashSet();
			Object[] stops = ((TagNode) results[0])
					.evaluateXPath("//a[@id='islandTransferShowLink1'][1]/text()");
			if (stops.length <= 0) {
				planeInfo.setStopOvers(Collections.<StopOverEntity> emptySet());
				return planeInfo;
			}
			Matcher m = Pattern.compile(
					"([0-9]{4})\\s+[^\\s]+\\s+[^(]+\\(([\\w]+)\\)").matcher(
					stops[0].toString());
			while (m.find()) {
				StopOverEntity entity = new StopOverEntity();
				entity.setArrTime(CrawlAdapterFactory.getFlightTime(
						taskQueue.getFlightDate(), m.group(1)));
				entity.setStopCity(m.group(2));
				entity.setPlaneInfoEntity(planeInfo);
				stopOverEntities.add(entity);
			}
			planeInfo.setStopOvers(stopOverEntities);
		} catch (Exception e) {
			throw new Exception("解析单程数据异常："+e.getMessage());
		}
		return planeInfo;
    }

    private List<Object> parseRoundway(Object fetchObject) {
        // TODO
        return Collections.emptyList();
    }

    @Override
    public Object fetch(String url) throws Exception {
        switch (getRouteType()) {
            case DOMESTIC_ONEWAYTRIP:
            case INTERNATIONAL_ONEWAY:
                return fetchOneway();
            default:
                return fetchRoundway();
        }
    }

    private Object fetchRoundway() throws Exception {
        Map<String, String> params = prepareFetchParams();
        List<AirAsiaFltKeys> fltKeyses = prepareRoundwayFltKeys(params);
        return fetchFltInfos(fltKeyses);
    }

    private List<AirAsiaFltKeys> prepareRoundwayFltKeys(Map<String, String> params) throws Exception {
        Map<String, String> fltKeysParams = prepareRoundwayFltKeysParams(params);
        // it will redirect to /select.aspx , so http client must follow the redirect
        HttpPost req = getBasePost("http://booking.airasia.com/search.aspx?culture=zh-CN", params);
        String html = super.excuteRequest(this.globalHttpClient, req, true);

        HtmlCleaner cleaner = new HtmlCleaner();
        //如果没有航班则需要抛出异常 。
        if(RegHtmlUtil.regMathcher(html, "该日期似乎无可选航班")){
        	throw new FlightInfoNotFoundException("没有符合搜索条件的航班");
        }
        TagNode root = cleaner.clean(html);
        Object[] rows = root.evaluateXPath("//table[@id='fareTable1_4']//tr[@class='rgRow']");
        if(rows.length==0){
        	rows=root.evaluateXPath("//table[@id='fareTable1_3']//tr[@class='rgRow']");
        }
        AirAsiaFltKeys first = new AirAsiaFltKeys();
        for (Object row : rows) {
            TagNode node = (TagNode) row;
            //ControlGroupSelectView$AvailabilityInputSelectView$market2 roundway
            Object[] fltKeys = node.evaluateXPath("//input[@type='radio'][@name='ControlGroupSelectView$AvailabilityInputSelectView$market1']/@value");
            if (fltKeys.length != 3) {
                continue;
            }
            first.economicFltKeys.add(fltKeys[0].toString());
            first.freqFltKeys.add(fltKeys[1].toString());
            first.businessFltKeys.add(fltKeys[2].toString());
        }

        // return trip.
        rows = root.evaluateXPath("//table[@id='fareTable2_4']//tr[@class='rgRow']");
        if(rows.length==0){
        	root.evaluateXPath("//table[@id='fareTable2_3']//tr[@class='rgRow']");
        }
        AirAsiaFltKeys second = new AirAsiaFltKeys();
        for (Object row : rows) {
            TagNode node = (TagNode) row;
            Object[] fltKeys = node.evaluateXPath("//input[@type='radio'][@name='ControlGroupSelectView$AvailabilityInputSelectView$market2']/@value");
            if (fltKeys.length != 3) {
                continue;
            }
            second.economicFltKeys.add(fltKeys[0].toString());
            second.freqFltKeys.add(fltKeys[1].toString());
            second.businessFltKeys.add(fltKeys[2].toString());
        }
        return ImmutableList.of(first, second);
    }

    private Map<String, String> prepareRoundwayFltKeysParams(Map<String, String> params) throws Exception {
        params = prepareRoundwayFltKeysParams(params);
        SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
        Date date = yyyyMMdd.parse(taskQueue.getReturnGrabDate());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);

        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListMarketDay2", String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH)));
        String yyyyMM = String.format("%s-%02d", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH));
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListMarketMonth2", yyyyMM);
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$RadioButtonMarketStructure", "RoundTrip");
        return params;
    }

    private Object fetchOneway() throws Exception {
        Map<String, String> params = prepareFetchParams();
        List<AirAsiaFltKeys> fltKeyses = prepareOnewayFltKeys(params);
        return fetchFltInfos(fltKeyses);
    }

    private List<AirAsiaFltInfos> fetchFltInfos(List<AirAsiaFltKeys> fltKeyses) {
        List<AirAsiaFltInfos> fltInfoses = new ArrayList<AirAsiaFltInfos>();
        for (AirAsiaFltKeys fltKeys : fltKeyses) {
            AirAsiaFltInfos fltInfos = new AirAsiaFltInfos();
            for (String fltKey : fltKeys.economicFltKeys) {
                String fltInfo = fetchFltInfoByKey(fltKey);
                if (StringUtils.isBlank(fltInfo)) {
                    continue;
                }
                fltInfos.economicFltInfos.add(fltInfo);
            }

            for (String fltKey : fltKeys.freqFltKeys) {
                String fltInfo = fetchFltInfoByKey(fltKey);
                if (StringUtils.isBlank(fltInfo)) {
                    continue;
                }
                fltInfos.freqFltInfos.add(fltInfo);
            }

            for (String fltKey : fltKeys.businessFltKeys) {
                String fltInfo = fetchFltInfoByKey(fltKey);
                if (StringUtils.isBlank(fltInfo)) {
                    continue;
                }
                fltInfos.businessFltInfos.add(fltInfo);
            }
            fltInfoses.add(fltInfos);
        }
        return fltInfoses;
    }

    private String fetchFltInfoByKey(String fltKey) {
        try {

            fltKey = encodeFltKey(fltKey);
            String url = String.format("http://booking.airasia.com/TaxAndFeeInclusiveDisplayAjax-resource.aspx?flightKeys=%s&numberOfMarkets=1&keyDelimeter=%%2C", fltKey);
            HttpGet req = new HttpGet(url);
            // pretend as a ajaxRequest
            req.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.116 Safari/537.36");
            req.addHeader("Referer", "http://booking.airasia.com/Select.aspx");
            req.addHeader("X-Requested-With", "XMLHttpRequest");
            return super.excuteRequest(this.globalHttpClient, req, true);
        } catch (Exception e) {
            logger.warn("Fetch fltInfo occurs error.", e);
            return EMPTY_FLT_INFO;
        }
    }

    private String encodeFltKey(String fltKey) {
        fltKey = StringUtils.substringBefore(fltKey, "@");
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < fltKey.length(); i++) {
            char c = fltKey.charAt(i);
            if (c == '^') {
                buf.append("%5E");
                continue;
            }
            if (c == '|') {
                buf.append("%7C");
                continue;
            }
            if (c == ' ') {
                buf.append("+");
                continue;
            }
            if (c == '/') {
                buf.append("%2F");
                continue;
            }
            if (c == ':') {
                buf.append("%3A");
                continue;
            }

            buf.append(c);
        }
        return buf.toString();
    }

    private List<AirAsiaFltKeys> prepareOnewayFltKeys(Map<String, String> params) throws Exception {
       Map<String, String> fltKeysParams = prepareOnewayFltKeysParams(params);
        // it will redirect to /select.aspx , so http client must follow the redirect
        HttpPost req = getBasePost("http://booking.airasia.com/search.aspx?culture=zh-CN", params);
        String html = super.excuteRequest(this.globalHttpClient, req, true);
        HtmlCleaner cleaner = new HtmlCleaner();
        //如果没有航班则需要抛出异常。
        if(RegHtmlUtil.regMathcher(html, "该日期似乎无可选航班")){
        	throw new FlightInfoNotFoundException("没有符合搜索条件的航班");
        }
        TagNode root = cleaner.clean(html);

        Object[] headers = root.evaluateXPath("//table[@id='fareTable1_4']/tbody/tr[1]/th[@id]");
        if(headers.length==0){
        	headers = root.evaluateXPath("//table[@id='fareTable1_3']/tbody/tr[1]/th[@id]");
        }
        int ecnomic = -1;
        int freq = -1;
        int business = -1;
        for (int i = 0; i < headers.length; i++) {
            String idval = ((TagNode) headers[i]).getAttributeByName("id");
            if (StringUtils.contains(idval, "lowfare")) {
                ecnomic = i;
                continue;
            }
            if (StringUtils.contains(idval, "hiflyer")) {
                freq = i;
                continue;
            }
            if (StringUtils.contains(idval, "premium")) {
                business = i;
            }
        }

        Object[] rows = root.evaluateXPath("//table[@id='fareTable1_4']//tr[@class='rgRow']");
        if(rows.length==0){
        	rows = root.evaluateXPath("//table[@id='fareTable1_3']//tr[@class='rgRow']");
        }
        AirAsiaFltKeys result = new AirAsiaFltKeys();
        for (Object row : rows) {
            TagNode node = (TagNode) row;
            Object[] fltKeys = node.evaluateXPath("//input[@type='radio'][@name='ControlGroupSelectView$AvailabilityInputSelectView$market1']/@value");
            if (ecnomic != -1 && ecnomic < fltKeys.length) {
                result.economicFltKeys.add(fltKeys[ecnomic].toString());
            }
            if (freq != -1 && freq < fltKeys.length) {
                result.freqFltKeys.add(fltKeys[freq].toString());
            }
            if (business != -1 && business < fltKeys.length) {
                result.businessFltKeys.add(fltKeys[business].toString());
            }
        }

        return ImmutableList.of(result);
    }

    private Map<String, String> prepareOnewayFltKeysParams(Map<String, String> params) throws Exception {
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$RadioButtonMarketStructure", "OneWay");
        params.put("ControlGroupSearchView_AvailabilitySearchInputSearchVieworiginStation1", taskQueue.getFromCity());
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$TextBoxMarketOrigin1", taskQueue.getFromCity());
        params.put("ControlGroupSearchView_AvailabilitySearchInputSearchViewdestinationStation1", taskQueue.getToCity());
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$TextBoxMarketDestination1", taskQueue.getToCity());
        params.put("ControlGroupSearchView$MultiCurrencyConversionViewSearchView$DropDownListCurrency", "default");

        SimpleDateFormat yyyyMM = new SimpleDateFormat("yyyy-MM", Locale.ENGLISH);
        SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
        Date from = yyyyMMdd.parse(taskQueue.getFlightDate());
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(from);

        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListMarketDay1", String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH)));
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListMarketMonth1", yyyyMM.format(calendar.getTime()));

        calendar.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH) + 3);
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListMarketDay2", String.format("%02d", calendar.get(Calendar.DAY_OF_MONTH)));
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListMarketMonth2", yyyyMM.format(calendar.getTime()));

        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListPassengerType_ADT", "1");
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListPassengerType_CHD", "0");
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListPassengerType_INFANT", "0");
        params.put("ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListSearchBy", "columnView");
        params.put("ControlGroupSearchView$ButtonSubmit", "搜索");
        return params;
    }

    private Map<String, String> prepareFetchParams() throws Exception {
        HttpGet req = new HttpGet("http://booking.airasia.com/search.aspx?culture=zh-CN");
        String html = super.excuteRequest(this.globalHttpClient, req, true);
        // asp.net tracing viewState to prevent csrf.
        HtmlCleaner cleaner = new HtmlCleaner();
        TagNode root = cleaner.clean(html);
        Object[] inputs = root.evaluateXPath("//input[@type='hidden']");
        Map<String, String> params = new HashMap<String, String>();
        for (Object input : inputs) {
            TagNode node = (TagNode) input;
            if (StringUtils.isBlank(node.getAttributeByName("name"))) {
                continue;
            }

            String paramName = node.getAttributeByName("name");
            if (StringUtils.equals("eventTarget", paramName)) {
                params.put("__EVENTTARGET", node.getAttributeByName("value"));
                continue;
            }
            if (StringUtils.equals("eventArgument", paramName)) {
                params.put("__EVENTARGUMENT", node.getAttributeByName("value"));
                continue;
            }
            if (StringUtils.equals("viewState", paramName)) {
                params.put("__VIEWSTATE", node.getAttributeByName("value"));
                continue;
            }
            params.put(paramName, node.getAttributeByName("value"));
        }
        return params;
    }

    private HttpClient globalHttpClient;


    @Override
    public boolean validateFetch(Object fetchObject) throws Exception {
        return true;
    }

    class AirAsiaFltKeys {
        List<String> freqFltKeys = new ArrayList<String>();
        List<String> economicFltKeys = new ArrayList<String>();
        List<String> businessFltKeys = new ArrayList<String>();
    }

    class AirAsiaFltInfos {
        List<String> freqFltInfos = new ArrayList<String>();
        List<String> economicFltInfos = new ArrayList<String>();
        List<String> businessFltInfos = new ArrayList<String>();
    }
    public static void main(String[] args) throws Exception {
        TaskModel taskModel = new TaskModel();
        taskModel.setFromCity("CAN");
        taskModel.setFromCityName("广州");
        taskModel.setToCity("SYD");
        taskModel.setToCityName("悉尼");
        taskModel.setFlightDate("2014-06-20");
        AirAsiaAdapter adapter = new AirAsiaAdapter(taskModel);
        List dd =  adapter.paraseToVo(adapter.fetch(null));
       for(Object obj:dd){
    	   SinglePlaneInfoEntity single = (SinglePlaneInfoEntity)obj;
    	   System.out.println("航班号："+single.getFlightNo());
    	   System.out.print("时间："+single.getStartTime());
    	   System.out.println("~"+single.getEndTime());
    	   
    	   System.out.println("中转:");
    	   for(TransitEntity tran : single.getTransits()){
    		   System.out.println(""+tran.getFromAirPort()+"~"+tran.getToAirPort()+"   时间："+tran.getStartTime()+"~"+tran.getEndTime());
    		   
    	   }
    	   
       }
       System.out.println(dd);
    }
}
